/*******************************************************************************
    Copyright 2019-2020 Sony Corporation

    $Id: //depot/bg/apps/audio/customer/Sony/LDAC-23.1-Earbud-Headset-QCC517x-QCC518x/audio/custom/kalimba/kymera/capabilities/ldac_decode/bufcnt/ldac_buffer_control.c#2 $
*******************************************************************************/
#include "ldac_dec_priv_lib.h"
#include "ldac_buffer_control.h"
#define tm_now()            get_time()
#define tm_greater(a, b)    time_gt(a, b)
#define tm_add(ts, nanos)   time_add(ts, nanos)

#define BC_SMA(bc) (1. * (bc)->sum / BC_NUM_FRAME_OBSERVE)
#define BC_SMA_LESSER(bc, value) ((bc)->sum < (value)*BC_NUM_FRAME_OBSERVE)
#define BC_SMA_GREATER(bc, value) ((bc)->sum > (value)*BC_NUM_FRAME_OBSERVE)

//memory for buffer control
struct buffer_control bc_mem;





struct buffer_control *bc_new(uint32 num_of_frames) {
    struct buffer_control *bc = &bc_mem;
    if (bc) {
        memset(bc, 0, sizeof(*bc));
        bc->frames_target = num_of_frames;
        bc->frames_upper = num_of_frames + BC_NUM_FRAME_THRESHOULD_UPPER;
        bc->frames_lower = num_of_frames + BC_NUM_FRAME_THRESHOULD_LOWER;
        bc->max_num_of_copy = MAX_NUM_OF_COPY;
        bc->control = 1;
        bc_reset(bc, FALSE);
    }
    return bc;
}


void bc_reset(struct buffer_control *bc, bool force_reset) {
    int i;
    const uint32 target = bc->frames_target;
    bc->pframes = bc->frames; /* reset cursor */
    for(i=0;i<BC_NUM_FRAME_OBSERVE;i++){
        bc->frames[i]=target;
    }
    bc->sum = BC_NUM_FRAME_OBSERVE * target;
    bc->num_of_copy = 0;
    /* if it is in the burst state and not reset forced, keep burst state. */
    if ( force_reset ){
        bc->stat = BC_STATE_IDLE;
        
    } else {
        if ( bc->stat == BC_STATE_BURST_RESUME ||
             bc->stat == BC_STATE_BURST_SKIP ||
             bc->stat == BC_STATE_BURST_ANALYZING ) {
             bc->stat = BC_STATE_BURST_RESUME;
        } else {
            bc->stat = BC_STATE_IDLE;
        }
    }
}

void bc_update(struct buffer_control *bc, int32 frame, timespec now_msk) {
    /* update sma */
    bc->sum += frame - *bc->pframes;

    *bc->pframes = frame;
    if (++bc->pframes == bc->frames + BC_NUM_FRAME_OBSERVE) {
        bc->pframes = bc->frames;
    }

    switch (bc->stat) {
        case BC_STATE_BURST_RESUME:
            bc->burst_end = tm_add(now_msk, bc->burst_life);
        case BC_STATE_BURST_SKIP:
        case BC_STATE_BURST_ANALYZING:
            /* update burst state. */
            if (frame > bc->frames_upper) {
                bc->stat = BC_STATE_BURST_SKIP;
                /* extend burst life waiting for settle down. */
                bc->burst_end = tm_add(now_msk, bc->burst_life);
            } else {
                bc->stat = BC_STATE_BURST_ANALYZING;
            }
            if (tm_greater(now_msk, bc->burst_end)) {
                bc_reset(bc, TRUE); /* force to quit burst state. */
            }
            break;
        case BC_STATE_IDLE:
            /* check to see to move state IDLE to ANALYZING */
            if (bc->pframes == bc->frames) {
                bc->stat = BC_STATE_ANALYZING;
                /* set next timing */
                bc->time = tm_add(now_msk, 1LL * MICROS);
                if(bc->time > LDAC_TIMER_MASK){
                    bc->time = bc->time - LDAC_TIMER_MASK;
                }
            }
            break;
        case BC_STATE_ANALYZING:
            /* check to see to move into SKIP/COPY state */
            if (tm_greater(now_msk, bc->time)) {
                if (BC_SMA_GREATER(bc, bc->frames_upper)) {
                    bc->stat = BC_STATE_SKIP;
                } else if (BC_SMA_LESSER(bc, bc->frames_lower)) {
                    bc->stat = BC_STATE_COPY;
                }
                /* update next timing (+1sec) */
                bc->time = tm_add(bc->time, 1LL * MICROS);
                if(bc->time > LDAC_TIMER_MASK){
                    bc->time = bc->time - LDAC_TIMER_MASK;
                }
            }
            break;
        case BC_STATE_SKIP:
        /* check to see to quit SKIP state */
            if (frame <= bc->frames_target) {
                bc_reset(bc, FALSE);
                bc->stat = BC_STATE_ANALYZING; /* force to move state ANA. */
                /* set next timing */
                bc->time = tm_add(now_msk, 1LL * MICROS);
                if(bc->time > LDAC_TIMER_MASK){
                    bc->time = bc->time - LDAC_TIMER_MASK;
                }
            }
        break;
        case BC_STATE_COPY:
        /* check to see to quit COPY state */
            if (frame >= bc->frames_target) {
                bc_reset(bc, FALSE);
                bc->stat = BC_STATE_ANALYZING; /* force to move state ANA. */
                /* set next timing */
                bc->time = tm_add(now_msk, 1LL * MICROS);
                if(bc->time > LDAC_TIMER_MASK){
                    bc->time = bc->time - LDAC_TIMER_MASK;
                }
            }
        break;
    }
}

void bc_burst(struct buffer_control *bc, int32 period,  timespec now) {
    bc->stat = BC_STATE_BURST_ANALYZING;
    bc->burst_life = period;
    bc->burst_end = tm_add(now, period);
}




